#pragma once

#include <nanobdd/common.h>
#include <nanobdd/node.h>

#include <vector>
#include <memory>

namespace nanobdd {

class Bdd {
public:
  Bdd() = default;
  Bdd(const Bdd& bdd) { node_ = bdd.node(); }
  Bdd(Node* node) : node_(node) {}
  // Bdd(int level, Bdd& low, Bdd& high) {
  //   node_ = std::make_shared<Node>(level, low.node(), high.node());
  // };

  Bdd& operator=(Bdd r) {
    node_ = r.node_;
    return *this;
  }

  // Bdd& operator=(const Bdd& r) {
  //   node_ = r.node_;
  //   return *this;
  // }

  Bdd operator&(const Bdd& r) const;
  Bdd operator|(const Bdd& r) const;
  Bdd operator!() const;
  bool operator==(const Bdd& r) const {
    return node_ == r.node();
  };
  bool operator!=(const Bdd& r) const {
    return node_ != r.node();
  };
  bool operator<(const Bdd& r) const {
    return node_ < r.node();
  };
  // int root() const { return root_; };

  Node* node() const {
    return node_;
  }
  int& level() const { return node_->level(); };

  Bdd negCof(int id) const;

  Bdd posCof(int id) const;

  bool isFalse() const;

  bool isTrue() const;

  // auto low() { return low_; }
  // auto high() { return high_; }

private:
  static Bdd combine(size_t x, const Bdd& low, Bdd& high, uint32_t opcode);
  Node* node_;
};

} // namespace nanobdd